import json
import re
from django import http
from django.contrib.auth import login, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect
from django.urls import reverse
from django.views import View

from apps.carts.utils import merge_cart_cookie_to_redis
from apps.goods.models import SKU
from utils.secret import SecretOauth
from apps.ausers.utils import generate_verify_email_url
from meiduo_mall.settings.dev import logger
from apps.ausers.models import User, Address
from utils.response_code import RETCODE
from django_redis import get_redis_connection

#1.注册页面
class RegisterView(View):
    def get(self, request):
        return render(request, 'register.html')

    #判正则函数
    def regular(self,use, reg, hint):
        if not re.match(reg, use):
            return http.HttpResponseForbidden(hint)




    def post(self, request):
        #3.接受参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        allow = request.POST.get('allow')
        sms_code = request.POST.get('msg_code')
        #3.校验参数
        #用户名 非空 正则 非重
        #密码  非空 正则
        #确认密码 非空 判等
        #手机号 非空 非重 正则
        #协议 勾选

        #判空 用户名 密码 确认密码 手机号
        if not all([username, password, password2, mobile]):
                    return http.HttpResponseForbidden("不允许为空")
        #正则 用户名 密码 手机号
        self.regular(username, r'^[a-zA-Z0-9_-]{5,20}$', '请输入5-20个字符的用户名')
        self.regular(password, r'^[a-zA-Z0-9]{8,20}$', '请输入8-20个字符的密码')
        self.regular(mobile, r'^1[345789]\d{9}$', '请输入有效手机号')

        #判等 确认密码
        if password2 != password:
            return http.HttpResponseForbidden("请输入相同的密码")

        #判断验证码
        # sms_redis_client = get_redis_connection('sms_code')
        # sms_redis_code = sms_redis_client.get('sms_%s' %mobile)
        # if sms_redis_code is None:
        #     return render(request, 'register.html', {'sms_code_errmsg': '短信验证码无效'})
        # if sms_redis_code.decode() != sms_code:
        #     return render(request, 'register.html', {'sms_code_errmsg': '输入短信验证码有误'})

        #勾选 美多协议
        if allow != 'on':
            return http.HttpResponseForbidden("请阅读美多协议，同意请勾选")


        #3.注册用户
        try:
            from apps.ausers.models import User
            user = User.objects.create_user(username=username, password=password, mobile=mobile)
        except Exception as e:
            logger.info(e)
            return render(request, 'register.html', {'register_message':"注册失败"})

        from django.contrib.auth import login
        #保持登录
        login(request,user)

        response = redirect(reverse('contents:index'))
        response.set_cookie("username", username, max_age=14 * 3600 * 24)

        # 跳转页面
        return response


#2.判断用户名是否重复
class UsernameCountView(View):
    def regular(self,use, reg, hint):
        if not re.match(reg, use):
            return http.HttpResponseForbidden(hint)

    def get(self,request, username):
        self.regular(username, r'^[a-zA-Z0-9_-]{5,20}$', '请输入5-20个字符的用户名')

        # if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
        #     return http.HttpResponseForbidden('请输入5-20个字符的用户名')


        if not all([username]):
                    return http.HttpResponseForbidden("不允许为空")
        try:

            count = User.objects.filter(username=username).count()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden("错误")

        return http.JsonResponse({'code':RETCODE.OK, 'errmsg':"查询成功", 'count':count})


#3.判断手机号是否重复
class MobileCountView(View):
    def regular(self,use, reg, hint):
        if not re.match(reg, use):
            return http.HttpResponseForbidden(hint)

    def get(self, request, mobile):
        self.regular(mobile, r'^1[345789]\d{9}$', '请输入有效手机号')

        if not all([mobile]):
                    return http.HttpResponseForbidden("不允许为空")

        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('错误')
        return http.JsonResponse({'code':RETCODE.OK, 'errmsg':"查询成功", 'count':count})


#4.登录页面
class LoginView(View):
    def get(self,request):
        return render(request,'login.html')

    #判正则函数
    def regular(self,use, reg, hint):
        if not re.match(reg, use):
            return http.HttpResponseForbidden(hint)

    def post(self, request ):
        #接受参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        remembered = request.POST.get('remembered')
        #校验判空判正则
        if not all([username, password]):
            return http.HttpResponseForbidden('参数不能为空')

        #判正则
        self.regular(username, r'^[a-zA-Z0-9_-]{5,20}$', '请输入5-20个字符的用户名')
        self.regular(password, r'^[a-zA-Z0-9]{8,20}$', '请输入8-20个字符的密码')
        #用户名
        from django.contrib.auth import authenticate
        user = authenticate(username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})
        #保持登录
        login(request, user)

        if remembered !='on':
            request.session.set_expiry(0)

        else:
            request.session.set_expiry(None)

        next = request.GET.get('next')
        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('contents:index'))
        response.set_cookie("username",username,max_age=14*3600*24)

        merge_cart_cookie_to_redis(request, user, response)

        #跳转页面
        return response

        #密码

        #记住登录


#5.退出登录
class LogoutView(View):
    def get(self,request):
        #退出登录
        logout(request)
        #删除cookie
        response = redirect(reverse('users:login'))

        response.delete_cookie('username')

        return response


#6.个人中心
class UserInfoView(LoginRequiredMixin, View):
    def get(self,request):
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }
        return render(request, 'user_center_info.html',context)


#7.个人中心修改邮箱
class EmailView(View):
    def put(self,request):
        # 1.接受参数
        email = json.loads(request.body.decode()).get('email')
        # 2.解析参数
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseForbidden('参数email有误')
        # 3.交互数据库
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})

        from celery_tasks.email.tasks import send_verify_email
        verify_url = generate_verify_email_url(request.user)
        send_verify_email.delay(email, verify_url)
        # 4.返回响应对象
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})


#8.激活邮箱
class VerifyEmailView(LoginRequiredMixin, View):
    def get(self,request):
        # 1.解析参数
        token = request.GET.get('token')
        # 2.解密
        token_dict = SecretOauth().loads(token)
        # 3.校验
        try:
            user = User.objects.get(id=token_dict['user_id'], email=token_dict['email'])
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('无效的token')
        # 4.修改
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('激活邮件失败')
        # 5.返回
        return redirect(reverse('users:info'))


#9.显示收货地址
class AddressView(LoginRequiredMixin, View):
    def get(self,request):
        user = request.user
        addresses = Address.objects.filter(user = user, is_deleted = False)
        address_dict_list = []
        for address in addresses:
            address_dict_list.append({
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            })
        context = {
            'default_address_id': user.default_address_id,
            'addresses': address_dict_list
        }

        return render(request, 'user_center_site.html', context)


#10.新增地址
class CreateAddressView(LoginRequiredMixin, View):
    def post(self,request):
        # count = Address.objects.filter(user = request.user, is_deleted=False).count()
        count = request.user.addresses.filter(is_deleted = False).count()
        if count > 20:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})
        #1.接受数据
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        #2.判空  判正则
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')
        #3.交互数据库
        try:
            address = Address.objects.create(
                user = request.user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel,
                email = email
            )
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        if not request.user.default_address:
            request.user.default_address = address
            request.user.save()
        #4.返回数据
        address_dict = {
            'id' : address.id,
            'title' : address.receiver,
            'receiver' : address.receiver,
            'province' : address.province.name,
            'city' : address.city.name,
            'district' : address.district.name,
            'place' : address.place,
            'mobile' : address.mobile,
            'tel' : address.tel,
            'email' : address.email
        }
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address':address_dict})


#11.修改地址
class UpdateDestroyAddressView(LoginRequiredMixin, View):
    def put(self,request, address_id):
        # 1.接受参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')
        # 2.校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数email有误')
        # 3.交互数据库
        try:
            Address.objects.filter(id=address_id).update(
                user=request.user,
                title=receiver,
                receiver=receiver,
                province_id=province_id,
                city_id=city_id,
                district_id=district_id,
                place=place,
                mobile=mobile,
                tel=tel,
                email=email
            )
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '更新地址失败'})

        #构建返回的数据格式
        address = Address.objects.get(id = address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }
        # 4.返回
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict})

    #逻辑删除地址
    def delete(self,request,address_id):

        try:
            address = Address.objects.get(id=address_id)
            address.is_deleted = True
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '删除地址失败'})

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除成功'})


#12.修改默认地址
class DefaultAddressView(LoginRequiredMixin, View):
    def put(self,request, address_id):

        try:
            # #修改default_address
            # address = Address.objects.get(id = address_id)
            # request.user.default_address = address
            # request.user.save()


            #直接修改default_address_id
            request.user.default_address_id = address_id
            request.user.save()

        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置默认地址成功'})


#13.修改标题
class UpdateTitleAddressView(LoginRequiredMixin, View):
    def put(self, request , address_id):
        #接受参数
        title_dict = json.loads(request.body.decode())
        title = title_dict.get('title')
        try:
            address = Address.objects.get(id = address_id)
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '设置地址标题失败'})

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '设置地址标题成功'})


#14.修改密码
class ChangePwdView(LoginRequiredMixin, View):
    def get(self, request):
        return render(request, 'user_center_pass.html')

    def post(self, request):
        #接受参数
        old_pwd = request.POST.get('old_pwd')
        new_pwd = request.POST.get('new_pwd')
        new_cpwd = request.POST.get('new_cpwd')
        #校验密码
        if not all([old_pwd, new_pwd, new_cpwd]):
            return http.HttpResponseForbidden('缺少必传参数')

        user = request.user
        result = user.check_password(old_pwd)
        if result == False:
            return render(request, 'user_center_pass.html', {'origin_pwd_errmsg':'原始密码错误'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_pwd):
            return http.HttpResponseForbidden('密码最少8位，最长20位')

        if new_pwd != new_cpwd:
            return http.HttpResponseForbidden('两次输入的密码不一致')
        #修改密码
        user.set_password(new_pwd)
        user.save()

        logout(request)

        response = redirect(reverse('users:login'))
        response.delete_cookie('username')
        #返回
        return response


#15.浏览记录
class HistoryBrowseView(LoginRequiredMixin, View):
    def get(self, request):
        #从数据库获取数据
        redis_client = get_redis_connection("history")
        redis_key = "history" + str(request.user.id)
        redis_sku_id = redis_client.lrange(redis_key, 0, -1)
        #遍历返回前端需要的格式
        skus = []
        for sku_id in redis_sku_id:
            sku = SKU.objects.get(id = sku_id)
            skus.append({
                'id':sku.id,
                'name':sku.name,
                'default_image_url':sku.default_image.url,
                'price':sku.price
            })
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})

    def post(self, request):
        # 1.接受参数
        sku_id = json.loads(request.body.decode()).get('sku_id')
        # 2.解析数据
        try:
            sku = SKU.objects.get(id = sku_id)
        except Exception as e:
            return http.HttpResponseForbidden("商品不存在")
        # 3.交互数据库
        redis_client = get_redis_connection("history")
        redis_key = "history" + str(request.user.id)
        p1 = redis_client.pipeline()
        p1.lrem(redis_key, 0, sku_id)
        p1.lpush(redis_key, sku_id)
        p1.ltrim(redis_key, 0, 4)
        p1.execute()
        # 4.返回
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
